/* CategoryList.cpp
Copyright (c) 2008 Michael Zahniser
Please note the license terms (MIT license) at the end of this document.

Function definitions for the CategoryList class.
*/

#include "CategoryList.h"

#include <fstream>

using std::ifstream;
using std::ofstream;
using std::ios;



// Count:
// Number of categories (i.e. number of separate TaskLists).
int CategoryList::Count() const
{
	return static_cast<int>(size());
}



// Name:
// Name of the category with the given index.
const string &CategoryList::Name(int index) const
{
	return (*this)[index].Name();
}



// Selection:
// Index of the currently selected category.
int CategoryList::Selection() const
{
	int i = 0;
	for(const_iterator it = begin(); it != category; ++it)
		++i;

	return i;
}



// operator[]:
// Get the category with the gven index.
const TaskList &CategoryList::operator[](int index) const
{
	return *GetIterator(index);
}



// Selected:
// Get the currently selected category.
const TaskList &CategoryList::Selected() const
{
	return *category;
}



// Load:
// Load all task lists in the given file.
bool CategoryList::Load(const string &path)
{
	// Store the path to this file. If this path is "<path>.txt", store
	// deleted items at "<path>_deleted.txt".
	filePath = path;
	deletedPath = path.substr(0, path.rfind('.')) + "_deleted.txt";
	
	return Append(path);
}



// Load:
// Load all task lists in the given file.
bool CategoryList::Load(istream &in)
{
	clear();
	return Append(in);
}



// Get the path this list was loaded from.
const string &CategoryList::FilePath() const
{
	return filePath;
}



// Save:
// Save changes to the file this list was loaded from.
void CategoryList::Save() const
{
	ofstream out(filePath.c_str(), ios::out | ios::binary);
	for(const_iterator it = begin(); it != end(); ++it)
		it->Save(out);
}



// Revert:
// Revert to the saved version of the data.
void CategoryList::Revert()
{
	clear();
	Load(filePath);
	SwitchToFirst();
}



// Restore:
// Load all categories that have been deleted and append them
// to the currently open set of categories.
void CategoryList::Resurrect()
{
	Append(deletedPath);
	
	// Delete the deleted file.
	ofstream clobber(deletedPath.c_str());
}



// Select:
// Select the given row.
void CategoryList::Select(int row)
{
	category = GetIterator(row);
}



// SwitchToFirst:
// Select the first category.
void CategoryList::SwitchToFirst()
{
	category = begin();
}



// SwitchToPrevious:
// Select the previous category. Wrap around if we're at the top of the list.
void CategoryList::SwitchToPrevious()
{
	if(category == begin())
		category = end();
	
	--category;
}



// SwitchToNext:
// Select the next category. Wrap around if we're at the bottom of the list.
void CategoryList::SwitchToNext()
{
	++category;
	
	if(category == end())
		category = begin();
}



// MoveUp:
// Move the selected category up in the list, unless it is already
// at the top of the list.
void CategoryList::MoveUp()
{
	if(category == begin())
		return;
	
	iterator previous = --iterator(category);
	splice(previous, *this, category);
}



// MoveDown:
// Move the selected category down in the list, unless it is already
// at the bottom of the list.
void CategoryList::MoveDown()
{
	iterator next = ++iterator(category);
	
	if(next == end())
		return;
	
	// Move the next item up to before this item.
	splice(category, *this, next);
}



// Add:
// Add a new category to the list, after the current one, and select the new category.
void CategoryList::Add()
{
	insert(++iterator(category), MutableTaskList());
	++category;
}



// Delete:
// Delete the current category. Select the category after it. If it was the last category,
// select the category before it intead.
void CategoryList::Delete()
{
	if(size() <= 1)
		return;
	
	ofstream out(deletedPath.c_str(), ios::out | ios::binary | ios::app | ios::ate);
	category->Save(out);

	iterator erasePoint = category++;
	
	erase(erasePoint);
	
	// If there is no category after the deleted one, select the one before it.
	if(category == end())
		--category;
}



// Append:
// Load tasks from the given file and append them to the current list.
bool CategoryList::Append(const string &path)
{
	// Open the file in binary input mode to avoid the differences in newline
	// characters between different operating systems.
	ifstream in(path.c_str(), ios::in | ios::binary);
	
	return Append(in);
}



bool CategoryList::Append(istream &in)
{
	// Read task lists until the end of file is reached.
	do {
		push_back(MutableTaskList());
	} while(back().Load(in));
	
	// Leave a null task in the list if it is the only item.
	bool success = (size() > 1);
	if(success)
		pop_back();
	
	SwitchToFirst();
	
	return success;
}



// GetIterator:
// Helper function. Get the element at the given index.
CategoryList::iterator CategoryList::GetIterator(int index)
{
	iterator it = begin();
	for( ; index--; ++it) {}
	
	return it;
}



// GetIterator:
// Helper function. Get the element at the given index.
CategoryList::const_iterator CategoryList::GetIterator(int index) const
{
	const_iterator it = begin();
	for( ; index--; ++it) {}
	
	return it;
}



/* Copyright (c) 2008 Michael Zahniser

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. */
